package com.ydc.ln.tutorial.ldap.test;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

public class LDAPUI {
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				JFrame frame = new LDAPFrame();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setVisible(true);
			}
		});
	}
}

class LDAPFrame extends JFrame {
	public static final int DEFAULT_WIDTH = 300;
	public static final int DEFAULT_HEIGHT = 200;

	private JButton findButton;
	private JButton saveButton;
	private JButton deleteButton;

	private JTextField uidField;
	private DataPanel dataPanel;
	private Component scrollPanel;

	private DirContext context;
	private String uid;
	private Attributes attrs;

	public LDAPFrame() {
		setTitle("LDAPUI");
		setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

		JPanel northPanel = new JPanel();
		northPanel.setLayout(new GridLayout(1, 2, 3, 1));
		northPanel.add(new JLabel("uid", SwingConstants.RIGHT));
		uidField = new JTextField();
		northPanel.add(uidField);
		add(northPanel, BorderLayout.NORTH);

		JPanel buttonPanel = new JPanel();
		add(buttonPanel, BorderLayout.SOUTH);

		findButton = new JButton("Find");
		findButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				findEntity();
			}
		});
		buttonPanel.add(findButton);
		
		saveButton = new JButton("Save");
		saveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				saveEntry();
			}
		});
		buttonPanel.add(saveButton);
		
		deleteButton = new JButton("Delete");
		deleteButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				deleteEntry();
			}
		});
		buttonPanel.add(deleteButton);
		
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				try {
					if(context != null) {
						context.close();
					}
				} catch (NamingException e) {
					e.printStackTrace();
				}
			}
		});
	}

	public void findEntity() {
		try {
			if (scrollPanel != null) {
				remove(scrollPanel);
			}
			String dn = "uid=" + uidField.getText() + ",ou=people,dc=mycompany,dc=com";
			System.out.println(dn);
			if (context == null) {
				context = getContext();
				attrs = context.getAttributes(dn);
				dataPanel = new DataPanel(attrs);
				scrollPanel = new JScrollPane(dataPanel);
				add(scrollPanel, BorderLayout.CENTER);
				validate();
				uid = uidField.getText();
			}
		} catch (NamingException e) {
			JOptionPane.showMessageDialog(this, e);
		} catch (IOException ie) {
			JOptionPane.showMessageDialog(this, ie);
		}
	}

	public void saveEntry() {
		try {
			if (dataPanel == null) {
				return;
			}
			if (context == null) {
				context = getContext();
			}
			if (uidField.getText().equals(uid)) {
				String dn = "uid=" + uidField.getText() + ",ou=people,dc=mycompany,dc=com";
				Attributes editedAttrs = dataPanel.getEditedAttributes();
				NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll();
				while (attrEnum.hasMore()) {
					Attribute attr = attrEnum.next();
					String id = attr.getID();
					Attribute editedAttr = editedAttrs.get(id);
					if (editedAttr != null && !attr.get().equals(editedAttr.get())) {
						context.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, new BasicAttributes(id, editedAttr.get()));
					}
				}
			} else {
				String dn = "uid=" + uidField.getText() + ",ou=people,dc=mycompany,dc=com";
				attrs = dataPanel.getEditedAttributes();
				Attribute objClass = new BasicAttribute("objectClass");
				objClass.add("uidObject");
				objClass.add("person");
				attrs.put(objClass);
				attrs.put("uid", uidField.getText());
				context.createSubcontext(dn, attrs);
			}
			findEntity();
		} catch (NamingException e) {
			JOptionPane.showMessageDialog(LDAPFrame.this, e);
			e.printStackTrace();
		} catch (IOException e) {
			JOptionPane.showMessageDialog(LDAPFrame.this, e);
			e.printStackTrace();
		}
	}

	public void deleteEntry() {
		try {
			String dn = "uid=" + uidField.getText() + ",ou=people,dc=mycompany,dc=com";
			if (context == null) {
				context = getContext();
			}
			context.destroySubcontext(dn);
			uidField.setText("");
			remove(scrollPanel);
			scrollPanel = null;
			repaint();
		} catch (NamingException e) {
			JOptionPane.showMessageDialog(LDAPFrame.this, e);
			e.printStackTrace();
		} catch (IOException e) {
			JOptionPane.showMessageDialog(LDAPFrame.this, e);
			e.printStackTrace();
		}
	}

	public static DirContext getContext() throws NamingException, IOException {
		Properties props = new Properties();
		// FileInputStream in = new FileInputStream(new File("ldapserver.properties"));
		// props.load(in);
		// in.close();
		
		InputStream in = LDAPFrame.class.getClassLoader().getResourceAsStream("ldapserver.properties");
		props.load(in);
		in.close();
		
		String url = props.getProperty("ldap.url");
		String username = props.getProperty("ldap.username");
		String password = props.getProperty("ldap.password");

		Hashtable<String, String> env = new Hashtable<String, String>();
		env.put(Context.SECURITY_PRINCIPAL, username);
		env.put(Context.SECURITY_CREDENTIALS, password);
		DirContext initial = new InitialDirContext(env);
		DirContext context = (DirContext) initial.lookup(url);

		return context;
	}
}

class DataPanel extends JPanel {
	public DataPanel(Attributes attrs) throws NamingException {
		setLayout(new GridLayout(0, 2, 3, 1));
		NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll();
		while (attrEnum.hasMore()) {
			Attribute attr = attrEnum.next();
			String id = attr.getID();
			NamingEnumeration<?> valueEnum = attr.getAll();
			while (valueEnum.hasMore()) {
				Object value = valueEnum.next();
				if (id.equals("userPassword")) {
					value = new String((byte[]) value);
				}
				JLabel idLabel = new JLabel(id, SwingConstants.RIGHT);
				JTextField valueField = new JTextField(value.toString());
				if (id.equals("objectClass")) {
					valueField.setEditable(false);
				}
				if (!id.equals("uid")) {
					add(idLabel);
					add(valueField);
				}
			}
		}
	}

	public Attributes getEditedAttributes() {
		Attributes attrs = new BasicAttributes();
		for (int i = 0; i < getComponentCount(); i += 2) {
			JLabel idLabel = (JLabel) getComponent(i);
			JTextField valueField = (JTextField) getComponent(i + 1);
			String id = idLabel.getText();
			String value = valueField.getText();
			if (id.equals("userPassword")) {
				attrs.put("userPassword", value.getBytes());
			} else if (!id.equals("") && !id.equals("objectClass")) {
				attrs.put(id, value);
			}
		}
		return attrs;
	}
}